home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / Menu.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  18.5 KB  |  589 lines  |  [TEXT/CWIE]

  1. // Menu.java
  2. // By Ned Etcode
  3. // Copyright 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Object subclass managing a collection of MenuItems.
  10.   * There are two Menu types: top-level main
  11.   * Menus and submenus (a menu invoked by a MenuItem). Both of these types
  12.   * of Menus can be used for AWT-based native Menus as well as IFC View-based
  13.   * pure java Menus. Top-level menus have an
  14.   * associated java.awt.MenuBar, while submenus have an associated
  15.   * java.awt.Menu. These are not utilized when the Menu is used within an
  16.   * IFC View-based structure.
  17.   * You generally create a new Menu and add MenuItems to it, configuring them
  18.   * with submenus as appropriate. The following code creates a Menu with a
  19.   * single MenuItem containing a single-item submenu:
  20.   * <pre>
  21.   *     menu = new Menu(true);
  22.   *     menuItem = menu.addItemWithSubmenu("Menu One");
  23.   *     menuItem.submenu().addItem("Item One", command, target);
  24.   * </pre>
  25.   * Once a Menu structure is created, it can be added to a MenuView within
  26.   * its Constructor method, or by calling <b>setMenu</b> on an existing
  27.   * MenuView. This MenuView can then be added to an InternalWindow or
  28.   * ExternalWindow with <b>setMenuView</b>. Additionally, you can add
  29.   * this Menu directly to an ExternalWindow with <b>setMenu</b>, and
  30.   * this will create an AWT-based native Menu on the top edge of the
  31.   * Window. The following code adds the same Menu created above to an
  32.   * existing ExternalWindow through both mechanisms:
  33.   * <pre>
  34.   *     externalWindow.setMenu(menu);
  35.   *
  36.   *     menuView = new MenuView(menu);
  37.   *     menuView.sizeToMinSize();
  38.   *     externalWindow.setMenuView(menuView);
  39.   * </pre>
  40.   *
  41.   * <I><b>Note:</b> The Menu class does not support the insertion of a
  42.   * submenu-less MenuItem into a top-level AWT-based Menu.</i>
  43.   *
  44.   * @see MenuItem, MenuView
  45.   * @note 1.0 completely rewritten
  46.   * @note 1.0 new method addItemAt taking a MenuItem description and index
  47.   * @note 1.0 handleCommandKeyEvent() checks if Control modifier is down
  48.   */
  49.  
  50. public class Menu implements Codable {
  51.     java.awt.Menu       awtMenu;
  52.     java.awt.MenuBar    awtMenuBar;
  53.     Application         application;
  54.     Vector              items;
  55.     MenuItem            superitem, prototypeItem;
  56.     Border              border;
  57.     Color               backgroundColor;
  58.     boolean             transparent = false;
  59.     MenuView            menuView = null;
  60.  
  61.     final static String    ITEMS_KEY = "items",
  62.                            SUPERITEM_KEY = "superitem",
  63.                            PROTOTYPEITEM_KEY = "prototypeItem",
  64.                            BORDER_KEY = "border",
  65.                            BACKGROUNDCOLOR_KEY = "backgroundColor",
  66.                            TRANSPARENT_KEY = "transparent";
  67.  
  68.  
  69.     /** Constructs a Menu.
  70.       * This Menu will be top-level by default.
  71.       */
  72.     public Menu() {
  73.         this(true);
  74.     }
  75.  
  76.     /** Constructs a Menu.
  77.       * If <b>isTopLevel</b> is <b>true</b>, this Menu will be a top-level
  78.       * Menu.
  79.       * This denotation is critical for AWT-based native Menus, and is
  80.       * not necessary with IFC View-based Menus.
  81.       */
  82.     public Menu(boolean isTopLevel) {
  83.         super();
  84.         MenuItem        protoItem;
  85.  
  86.         items = new Vector();
  87.  
  88.         backgroundColor = Color.lightGray;
  89.         setBorder(new MenuBorder(this));
  90.  
  91.         if (isTopLevel) {
  92.             awtMenuBar = new java.awt.MenuBar();
  93.         } else {
  94.             awtMenu = new java.awt.Menu("");
  95.         }
  96.  
  97.         protoItem = new MenuItem();
  98.         setPrototypeItem(protoItem);
  99.     }
  100.  
  101.     /** Returns <b>true</b> if the Menu is a top-level menu.
  102.       */
  103.     boolean isTopLevel() {
  104.         if (superitem != null && superitem.supermenu() != null) {
  105.             return false;
  106.         }
  107.         return true;
  108.     }
  109.  
  110.     /** Sets the MenuItem that contains this Menu. If this Menu is a top-level
  111.       * Menu, this variable is null. You should never call this method
  112.       * directly.
  113.       */
  114.     void setSuperitem(MenuItem item) {
  115.         superitem = item;
  116.     }
  117.  
  118.     /** Returns the MenuItem that contains this Menu. If this Menu is a
  119.       * top-level menu, this varaible is null.
  120.       * @see #setSuperitem
  121.       */
  122.     MenuItem superitem() {
  123.         return superitem;
  124.     }
  125.  
  126.     /** Sets the prototype MenuItem for this Menu.  Whenever the Menu needs a
  127.       * new MenuItem, it clones the prototype MenuItem.
  128.       */
  129.     public void setPrototypeItem(MenuItem prototype) {
  130.         prototypeItem = prototype;
  131.     }
  132.  
  133.     /** Returns the Menu's prototype MenuItem.
  134.       * @see #setPrototypeItem
  135.       */
  136.     public MenuItem prototypeItem() {
  137.         return prototypeItem;
  138.     }
  139.  
  140.     /** Sets the Color drawn behind transparent MenuItems, and any area in
  141.       * the Menu not covered by MenuItems. This has no effect on AWT-based
  142.       * native Menus.
  143.       *
  144.       */
  145.     public void setBackgroundColor(Color color) {
  146.         backgroundColor = color;
  147.     }
  148.  
  149.     /** Returns the background color.
  150.       * @see #setBackgroundColor
  151.       *
  152.       */
  153.     public Color backgroundColor() {
  154.         return backgroundColor;
  155.     }
  156.  
  157.     /** Sets the Menu's Border. The Menu draws this Border around its smaller
  158.       * inactive state and around its window when a MenuItem's submenu is
  159.       * active. You can customize a Menu's look by setting a different Border.
  160.       * This has no effect on AWT-based native Menus.
  161.       *
  162.       */
  163.     public void setBorder(Border aBorder) {
  164.         if (aBorder == null) {
  165.             border = EmptyBorder.emptyBorder();
  166.         } else {
  167.             border = aBorder;
  168.         }
  169.     }
  170.  
  171.     /** Returns the Menu's Border.
  172.       * @see #setBorder
  173.       *
  174.       */
  175.     public Border border() {
  176.         return border;
  177.     }
  178.  
  179.     /** Sets the Menu to be transparent or opaque. This has no effect on
  180.       * AWT-based native Menus.
  181.       *
  182.       */
  183.     public void setTransparent(boolean flag) {
  184.         transparent = flag;
  185.     }
  186.  
  187.     /** Overridden to return <b>true</b> if the Menu is transparent.
  188.       * @see #setTransparent
  189.       *
  190.       */
  191.     public boolean isTransparent() {
  192.         return transparent;
  193.     }
  194.  
  195.     /** Creates a new MenuItem with characteristics derived from
  196.       * the prototype. If <b>isCheckbox</b> is true, this will be a checkbox
  197.       * MenuItem. This MenuItem is not added to the Menu.
  198.       */
  199.     MenuItem createItem(boolean isCheckbox) {
  200.         MenuItem menuItem;
  201.  
  202.         menuItem = (MenuItem)prototypeItem().clone();
  203.  
  204.         if (!isCheckbox) {
  205.             menuItem.foundationMenuItem = new FoundationMenuItem("",
  206.                                                                  menuItem);
  207.         } else {
  208.             menuItem.foundationMenuItem =
  209.                 new FoundationCheckMenuItem("", menuItem);
  210.             menuItem.setCheckedImage(Bitmap.bitmapNamed(
  211.                                "netscape/application/RadioButtonOn.gif"));
  212.             menuItem.setUncheckedImage(Bitmap.bitmapNamed(
  213.                                "netscape/application/RadioButtonOff.gif"));
  214.             menuItem.setImage(menuItem.uncheckedImage());
  215.             menuItem.setSelectedImage(menuItem.uncheckedImage());
  216.         }
  217.  
  218.         // ALERT.  Must set Font because the new FoundationMenuItem by
  219.         // default has a null java.awt.Font.
  220.         menuItem.setFont(prototypeItem().font());
  221.  
  222.         return menuItem;
  223.     }
  224.  
  225.     /** Creates a new Menu for use as a MenuItem's submenu. Called by
  226.       * <b>addItemWithSubmenu()</b>. Subclasses should override this method
  227.       * to return a subclass instance.
  228.       */
  229.     protected Menu createMenuAsSubmenu() {
  230.         Menu      menu;
  231.         MenuItem  item;
  232.  
  233.         menu = new Menu(false);
  234.         menu.setPrototypeItem(createItem(false));
  235.         menu.setBackgroundColor(backgroundColor());
  236.         //menu.setBorder(border);
  237.         return menu;
  238.     }
  239.  
  240.     /** Adds a new MenuItem, containing a submenu, to the end of this
  241.       * Menu, with title <b>title</b>.
  242.       */
  243.     public MenuItem addItemWithSubmenu(String title) {
  244.         MenuItem menuItem;
  245.         Menu menu;
  246.  
  247.         menuItem = createItem(false);
  248.         menuItem.setTitle(title);
  249.  
  250.         menu = createMenuAsSubmenu();
  251.         menuItem.setSubmenu(menu);
  252.         addItemAt(menuItem, itemCount());
  253.         return menuItem;
  254.     }
  255.  
  256.     /** Adds a new MenuItem to the end of this Menu, with title <b>title</b>,
  257.       * command <b>command</b> and Target <b>target</b>.
  258.       */
  259.     public MenuItem addItem(String title, String command, Target target) {
  260.         return addItem(title, (char)0, command, target);
  261.     }
  262.  
  263.     /** Adds a new MenuItem to the end of this Menu, with title <b>title</b>,
  264.       * command <b>command</b> and Target <b>target</b>. If <b>isCheckbox</b>
  265.       * is true, this adds a checkbox MenuItem.
  266.       *
  267.       */
  268.     public MenuItem addItem(String title, String command, Target target,
  269.                             boolean isCheckbox) {
  270.         return addItem(title, (char)0, command, target, isCheckbox);
  271.     }
  272.  
  273.     /** Adds a new MenuItem to the end of this Menu, with title <b>title</b>,
  274.       * command key equivalent <b>key</b>, command <b>command</b> and Target
  275.       * <b>target</b>.
  276.       */
  277.     public MenuItem addItem(String title, char key, String command,
  278.                             Target target) {
  279.         return addItem(title, key, command, target, false);
  280.     }
  281.  
  282.     /** Adds a new MenuItem to the end of this Menu, with title <b>title</b>,
  283.       * command key equivalent <b>key</b>, command <b>command</b> and Target
  284.       * <b>target</b>. If <b>isCheckbox</b> is true, this will add a checkbox
  285.       * MenuItem.
  286.       *
  287.       */
  288.     public MenuItem addItem(String title, char key, String command,
  289.                             Target target, boolean isCheckbox) {
  290.         return addItemAt(title, key, command, target, isCheckbox, itemCount());
  291.     }
  292.  
  293.     /** Adds a new MenuItem at the specified <b>index</b> in this Menu, with
  294.       * title <b>title</b>,
  295.       * command key equivalent <b>key</b>, command <b>command</b> and Target
  296.       * <b>target</b>. If <b>isCheckbox</b> is true, this will add a checkbox
  297.       * MenuItem.
  298.       *
  299.       */
  300.     public MenuItem addItemAt(String title, char key,
  301.                               String command, Target target,
  302.                               boolean isCheckbox, int index) {
  303.         MenuItem menuItem;
  304.  
  305.         menuItem = createItem(isCheckbox);
  306.         menuItem.setSubmenu(null);
  307.         menuItem.setSupermenu(this);
  308.         menuItem.setCommandKey(key);
  309.         menuItem.setTitle(title);
  310.         menuItem.setTarget(target);
  311.         menuItem.setCommand(command);
  312.         addItemAt(menuItem, index);
  313.         return menuItem;
  314.     }
  315.  
  316.     /** Adds a separator line to this Menu at the current position.
  317.       *
  318.       */
  319.     public MenuItem addSeparator() {
  320.         MenuItem  menuItem = null;
  321.  
  322.         menuItem = createItem(false);
  323.         menuItem.setSeparator(true);
  324.         addItemAt(menuItem, itemCount());
  325.         return menuItem;
  326.     }
  327.  
  328.     /** Returns the index of the specified MenuItem.
  329.       */
  330.     public int indexOfItem(MenuItem item) {
  331.         return items.indexOf(item);
  332.     }
  333.  
  334.     /** Returns the number of MenuItems this Menu contains.
  335.       */
  336.     public int itemCount() {
  337.         return items.count();
  338.     }
  339.  
  340.     /** Returns the MenuItem at <b>index</b>.
  341.       */
  342.     public MenuItem itemAt(int index) {
  343.         return (MenuItem)items.elementAt(index);
  344.     }
  345.  
  346.     /** Adds the MenuItem <b>menuItem</b> at <b>index</b>.
  347.       */
  348.     public void addItemAt(MenuItem menuItem, int index) {
  349.         java.awt.Menu menu;
  350.         int i;
  351.  
  352.         menuItem.setSupermenu(this);
  353.         if (menuItem.hasSubmenu()) {
  354.             menu = menuItem.submenu().awtMenu();
  355.  
  356.             menu.setLabel(menuItem.title());
  357.             menu.setFont(AWTCompatibility.awtFontForFont(menuItem.font()));
  358.             if (isTopLevel()) {
  359.                 if (awtMenuBar != null) {
  360.                     awtMenuBar.add(menu);
  361.                 }
  362.             } else {
  363.                 if (awtMenu != null) {
  364.                     awtMenu.add(menu);
  365.                 }
  366.             }
  367.         } else {
  368.             if (isTopLevel()) {
  369.                 // this will be an ugly hack to allow top level MenuItems
  370.             } else {
  371.                 if (awtMenu != null) {
  372.                     if (menuItem.isSeparator()) {
  373.                         awtMenu.addSeparator();
  374.                     } else {
  375.                         awtMenu.add(menuItem.foundationMenuItem());
  376.                     }
  377.                 }
  378.             }
  379.         }
  380.         items.insertElementAt(menuItem, index);
  381.         for (i = 0; i < itemCount(); i++) {
  382.             itemAt(i).setTitle(itemAt(i).title());
  383.         }
  384.     }
  385.  
  386.     /** Removes <b>menuItem</b> from the Menu.
  387.       */
  388.     public void removeItem(MenuItem menuItem) {
  389.         items.removeElement(menuItem);
  390.         if (isTopLevel()) {
  391.             awtMenuBar.remove(menuItem.foundationMenuItem());
  392.         } else {
  393.             awtMenu.remove(menuItem.foundationMenuItem());
  394.         }
  395.     }
  396.  
  397.     /** Removes the MenuItem at <b>index</b>.
  398.       */
  399.     public void removeItemAt(int index) {
  400.         items.removeElementAt(index);
  401.         if (isTopLevel()) {
  402.             awtMenuBar.remove(index);
  403.         } else {
  404.             awtMenu.remove(index);
  405.         }
  406.     }
  407.  
  408.     /** Replaces the MenuItem at <b>index</b> with <b>menuItem</b>. This has
  409.       * no effect on AWT-based native Menus.
  410.       *
  411.       */
  412.     public void replaceItemAt(int index, MenuItem menuItem) {
  413.         items.replaceElementAt(index, menuItem);
  414.     }
  415.  
  416.     /** Replaces the MenuItem with the new MenuItem. This has no effect
  417.       * on AWT-based native Menus.
  418.       *
  419.       */
  420.     public void replaceItem(MenuItem item, MenuItem newItem) {
  421.         int i;
  422.  
  423.         i = indexOfItem(item);
  424.         if (i != -1) {
  425.             replaceItemAt(i, newItem);
  426.         }
  427.     }
  428.  
  429.     /** Called by <b>mouseUp()</b> in MenuView so that selected MenuItems
  430.       * can send
  431.       * their commands.  The selected MenuItem is passed in as <b>data</b>,
  432.       * so if it is null, no command is sent.  You should never call this
  433.       * method directly.
  434.       */
  435.     public void performCommand(String command, Object data) {
  436.         MenuItem  item;
  437.  
  438.         if (data != null) {
  439.             item = (MenuItem)data;
  440.             item.setState(!item.state());
  441.             item.sendCommand();
  442.         }
  443.     }
  444.  
  445.     /** Returns the largest title width of all of the Menu's MenuItems.
  446.       */
  447.     int minItemWidth() {
  448.         int          i, width, maxWidth;
  449.  
  450.         maxWidth = 0;
  451.         for (i = 0; i < itemCount(); i++) {
  452.             width = itemAt(i).minWidth();
  453.  
  454.             if (width > maxWidth) {
  455.                 maxWidth = width;
  456.             }
  457.         }
  458.         return maxWidth;
  459.     }
  460.  
  461.     /** Examines all MenuItems for a command key equivalent.  If the Menu
  462.       * finds a match, this method performs the corresponding command and
  463.       * returns <b>true</b>.
  464.       */
  465.     public boolean handleCommandKeyEvent(KeyEvent event) {
  466.         MenuItem     item;
  467.         boolean      eventHandled = false;
  468.  
  469.         if (!event.isControlKeyDown()) {
  470.             return false;
  471.         }
  472.  
  473.         item = itemForKeyEvent(event);
  474.         if (item != null) {
  475.             item.sendCommand();
  476.             eventHandled = true;
  477.         }
  478.         return eventHandled;
  479.     }
  480.  
  481.     MenuItem itemForKeyEvent(KeyEvent event) {
  482.         int      i;
  483.         MenuItem item, menuItem = null;
  484.  
  485.         if (!event.isControlKeyDown()) {
  486.             return null;
  487.         }
  488.  
  489.         for (i = 0; i < itemCount() && menuItem == null; i++) {
  490.             item = itemAt(i);
  491.             if (!item.isEnabled()) {
  492.                 continue;
  493.             }
  494.             if (item.hasSubmenu()) {
  495.                 menuItem = item.submenu().itemForKeyEvent(event);
  496.             } else {
  497.                 // ALERT.  this should really compare the event.key to
  498.                 // the MenuItem's commandkey as a char, not an int
  499.                 if ((int)item.commandKey() == event.key + 64) {
  500.                     menuItem = item;
  501.                 }
  502.             }
  503.         }
  504.         return menuItem;
  505.     }
  506.  
  507.     /** Returns the java.awt.Menu associated with this Menu. This variable
  508.       * is only set in submenus.
  509.       * @see Menu#awtMenuBar
  510.       */
  511.     java.awt.Menu awtMenu() {
  512.         return awtMenu;
  513.     }
  514.  
  515.     /** Returns the java.awt.Menu associated with this Menu. This variable
  516.       * is only set if this is a top-level Menu.
  517.       * @see Menu#awtMenu
  518.       */
  519.     java.awt.MenuBar awtMenuBar() {
  520.         return awtMenuBar;
  521.     }
  522.  
  523.     /** Sets the application associated with this menu. This variable is
  524.       * only set if this is a top-level Menu. You never call this method
  525.       * directly, but rather through ExternalWindow in its setMenu method.
  526.       * The Application is used by FoundationMenuItem to create an Event.
  527.       */
  528.     void setApplication(Application app) {
  529.         application = app;
  530.     }
  531.  
  532.     /** Returns the application associated with this menu. This variable is
  533.       * only set if this is a top-level Menu.
  534.       */
  535.     Application application() {
  536.         return application;
  537.     }
  538.  
  539.     /** Describes the Menu class' information.
  540.       * @see Codable#describeClassInfo
  541.       */
  542.     public void describeClassInfo(ClassInfo info) {
  543.         info.addClass("netscape.application.Menu", 1);
  544.  
  545.         info.addField(ITEMS_KEY, OBJECT_TYPE);
  546.         info.addField(SUPERITEM_KEY, OBJECT_TYPE);
  547.         info.addField(PROTOTYPEITEM_KEY, OBJECT_TYPE);
  548.  
  549.         info.addField(BORDER_KEY, OBJECT_TYPE);
  550.         info.addField(BACKGROUNDCOLOR_KEY, OBJECT_TYPE);
  551.  
  552.         info.addField(TRANSPARENT_KEY, BOOLEAN_TYPE);
  553.     }
  554.  
  555.     /** Encodes the Menu instance.
  556.       * @see Codable#encode
  557.       */
  558.     public void encode(Encoder encoder) throws CodingException {
  559.         encoder.encodeObject(ITEMS_KEY, items);
  560.         encoder.encodeObject(SUPERITEM_KEY, superitem);
  561.         encoder.encodeObject(PROTOTYPEITEM_KEY, prototypeItem);
  562.  
  563.         encoder.encodeObject(BORDER_KEY, border);
  564.         encoder.encodeObject(BACKGROUNDCOLOR_KEY, backgroundColor);
  565.  
  566.         encoder.encodeBoolean(TRANSPARENT_KEY, transparent);
  567.     }
  568.  
  569.     /** Decodes the Menu instance.
  570.       * @see Codable#decode
  571.       */
  572.     public void decode(Decoder decoder) throws CodingException {
  573.         items = (Vector)decoder.decodeObject(ITEMS_KEY);
  574.         superitem = (MenuItem)decoder.decodeObject(SUPERITEM_KEY);
  575.         prototypeItem = (MenuItem)decoder.decodeObject(PROTOTYPEITEM_KEY);
  576.  
  577.         border = (Border)decoder.decodeObject(BORDER_KEY);
  578.         backgroundColor = (Color)decoder.decodeObject(BACKGROUNDCOLOR_KEY);
  579.  
  580.         transparent = decoder.decodeBoolean(TRANSPARENT_KEY);
  581.     }
  582.  
  583.     /** Finishes the Menu's unarchiving.
  584.       * @see Codable#finishDecoding
  585.       */
  586.     public void finishDecoding() throws CodingException {
  587.     }
  588. }
  589.